#include<iostream>
#include<pthread.h>
#include<queue>
#include<string>
#include<unistd.h>
#include<sys/wait.h>
#include"Task.hpp"
#include"Log.hpp"

#define NUM 5

class PthreadPool {
    private:
      std::queue<Task> _blockQueue;
      pthread_cond_t _cond;
      pthread_mutex_t _lock;
      static PthreadPool* _pthreadPool;
    private:
      PthreadPool() = default; 
      PthreadPool(const PthreadPool& t) = delete;
      PthreadPool& operator=(const PthreadPool& t) = delete;
      void Wait() {
           pthread_cond_wait(&_cond, &_lock);
      }
      void WakeUp() {
           pthread_cond_signal(&_cond);
      }
      void Lock() {
           pthread_mutex_lock(&_lock);
      }
      void UnLock() {
           pthread_mutex_unlock(&_lock);
      }
      bool IsEmpty() {
          return _blockQueue.size() == 0;
      }
    public:
      static PthreadPool* GetInstance(){
        static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
        if (_pthreadPool == nullptr) {
            pthread_mutex_lock(&mtx);
            if (_pthreadPool == nullptr) {
                _pthreadPool = new PthreadPool();
                _pthreadPool -> PthreadPoolInit(); 
                LOG(INFO, "PthreadPoolInit done");
            }
            pthread_mutex_unlock(&mtx);
        }
        return _pthreadPool;
      }
      static void* ThreadHandler(void* arg) {
            PthreadPool* _this = (PthreadPool*)(arg); 
            while(true) {
              _this->Lock();
              while (_this -> IsEmpty()) { /*while防止假唤醒*/
                   _this->Wait(); 
                   LOG(INFO , "pthread_t id :" + std::to_string(pthread_self()));
              }
              LOG(INFO, "I am awake ");
              Task t; 
              _this->Pop(t);

              LOG(INFO, "I am get task");
              _this->UnLock();
          
              LOG(INFO, "TaskHander begin..");
              t.TaskHander(); /*处理逻辑的代码放在临界区外面*/
              LOG(INFO, "TaskHander done..");
            }
            return nullptr;
      }
      void PthreadPoolInit() {
           pthread_mutex_init(&_lock, nullptr);
           pthread_cond_init(&_cond, nullptr);
           for (int i = 0; i < NUM; i++) {
               pthread_t pid;
               pthread_create(&pid, nullptr, ThreadHandler, (void*)this);
               pthread_detach(pid);
           }
      }
      void Push(Task& task) {
           Lock();
           _blockQueue.push(task);
           LOG(INFO, "Push one task...");
           UnLock();
           WakeUp();/*唤醒线程*/
      }
      void Pop(Task& task) {
           task = _blockQueue.front();
           _blockQueue.pop();
      }
      ~PthreadPool() {
           pthread_mutex_destroy(&_lock);
           pthread_cond_destroy(&_cond);
           delete _pthreadPool;
           _pthreadPool = nullptr;
      }
};
PthreadPool* PthreadPool:: _pthreadPool = nullptr;
